//
// Created by 徐岩 on 2024/8/6.
//

#include "JvmCallback.h"

JvmCallback::JvmCallback(_JavaVM *javaVM, JNIEnv *jniEnv, jobject jobj) {
    this->javaVM = javaVM;
    this->jniEnv = jniEnv;
    this->jobj = jniEnv->NewGlobalRef(jobj);
    jclass jlz = jniEnv->GetObjectClass(jobj);
    jmid_onCameraFrame = jniEnv->GetMethodID(jlz, "onCameraFrame", "([B)V");
    jmid_onSaveYoloData = jniEnv->GetMethodID(jlz, "saveYoloData", "(Ljava/lang/String;Ljava/lang/String;)V");
}

void JvmCallback::onCameraFrame(int type, unsigned char *data, int width,int height) {
    int len = width * height * 3 / 2;
    auto * yuv = new unsigned char [len];
    rgbaToYuv(width, height, data, reinterpret_cast<unsigned char *>(yuv), RGB_YUV420SP);
    if (type == MAIN_THREAD) {
        jbyteArray jdata = jniEnv->NewByteArray(len);
        jniEnv->SetByteArrayRegion(jdata, 0, len, (jbyte *) yuv);
        jniEnv->CallVoidMethod(jobj, jmid_onCameraFrame, jdata);
        jniEnv->DeleteLocalRef(jdata);
    } else {
        JNIEnv *_jniEnv;
        if (javaVM->AttachCurrentThread(&_jniEnv, nullptr) != JNI_OK) {
            __android_log_print(ANDROID_LOG_WARN, "JvmCallback", "onSaveYoloData===>error");
            return;
        }
        jbyteArray jdata = _jniEnv->NewByteArray(len);
        _jniEnv->SetByteArrayRegion(jdata, 0, len, (jbyte *) yuv);
        _jniEnv->CallVoidMethod(jobj, jmid_onCameraFrame, jdata);
        _jniEnv->DeleteLocalRef(jdata);
        javaVM->DetachCurrentThread();
    }
    delete []yuv;
}

void JvmCallback::onSaveYoloData(int type,const char* path_dir, const char *json) {
    if (type == MAIN_THREAD) {
        jstring path_dir_jstr = jniEnv->NewStringUTF(path_dir);
        jstring json_jstr = jniEnv->NewStringUTF(json);
        jniEnv->CallVoidMethod(jobj, jmid_onSaveYoloData, json_jstr,path_dir_jstr);
        jniEnv->DeleteLocalRef(path_dir_jstr);
        jniEnv->DeleteLocalRef(json_jstr);
    }else{
        JNIEnv *_jniEnv;
        if (javaVM->AttachCurrentThread(&_jniEnv, nullptr) != JNI_OK) {
            __android_log_print(ANDROID_LOG_WARN, "JvmCallback", "onSaveYoloData===>error");
            return;
        }
        __android_log_print(ANDROID_LOG_WARN, "JvmCallback", "onSaveYoloData===>111111");
        jstring path_dir_jstr = _jniEnv->NewStringUTF(path_dir);
        __android_log_print(ANDROID_LOG_WARN, "JvmCallback", "onSaveYoloData===>json:%s",json);
        jstring json_jstr = _jniEnv->NewStringUTF(json);
        __android_log_print(ANDROID_LOG_WARN, "JvmCallback", "onSaveYoloData===>333333");
        _jniEnv->CallVoidMethod(jobj, jmid_onSaveYoloData, json_jstr,path_dir_jstr);
        _jniEnv->DeleteLocalRef(path_dir_jstr);
        _jniEnv->DeleteLocalRef(json_jstr);
        javaVM->DetachCurrentThread();
        delete[] json;
    }

}

void JvmCallback::onCameraFrame(int type, cv::Mat &rgb) {
    int width = 480;
    int height = 640;
    int len = width * height * 3 / 2;
    auto * yuv = new unsigned char [len];
    rgbaToYuv(width, height, rgb.data, reinterpret_cast<unsigned char *>(yuv), RGB_YUV420SP);

    delete [] yuv;

}

void JvmCallback:: rgbaToYuv(int width,int height,unsigned char * rgb,unsigned char * yuv,int type){
    const int frameSize = width * height;
    const int yuvType=(type&0x10000)>>16;
    const int byteRgba=(type&0x0F000)>>12;
    const int rShift=(type&0x00F00)>>8;
    const int gShift=(type&0x000F0)>>4;
    const int bShift= (type&0x0000F);
    const int uIndex=0;
    const int vIndex=yuvType; //yuvType为1表示YUV420p,为0表示420sp

    int yIndex = 0;
    int uvIndex[2]={frameSize,frameSize+frameSize/4};

    unsigned char R, G, B, Y, U, V;
    unsigned int index = 0;
    for (int j = 0; j < height; j++) {
        for (int i = 0; i < width; i++) {
            index = j * width + i;

            R = rgb[index*byteRgba+rShift]&0xFF;
            G = rgb[index*byteRgba+gShift]&0xFF;
            B = rgb[index*byteRgba+bShift]&0xFF;

            Y = y(R,G,B);
            U = u(R,G,B);
            V = v(R,G,B);

            yuv[yIndex++] = color(Y);
            if (j % 2 == 0 && index % 2 == 0) {
                yuv[uvIndex[uIndex]++] =color(U);
                yuv[uvIndex[vIndex]++] =color(V);
            }
        }
    }
}

JvmCallback::~JvmCallback() {
    if (jobj) {
        jniEnv->DeleteGlobalRef(jobj);
    }

}




